extends Spatial
class_name Level

var repeat_time: float = 0.0

onready var camera: Camera = $CameraCenter/SimpleCamera
onready var tween: Tween = $Tween

var polyhedra: Array = []
var selected_poly: CuboidPolyhedron = null

# get the tile at specified position
func get_tile(md: MapData, pos: Vector3, excluded_polyhedra: Array = []) -> Dictionary:
	# check map data
	if md != null:
		var tt: TileType = md.get_tile(pos)
		if tt != null:
			return {
				"map_data": md,
				"pos": pos,
				"tile": tt,
			}

	# check polyhedron
	for obj in polyhedra:
		var poly: CuboidPolyhedron = obj as CuboidPolyhedron
		if poly != null and poly.map_data == md and not poly in excluded_polyhedra and poly.is_hittest_object():
			var local_pos: Vector3 = PolyhedronPosition.map_global_to_local(poly.map_position, pos)
			var tile: int = poly.get_tile(local_pos)
			if tile > 0:
				return {
					"polyhedron": poly,
					"local_pos": local_pos,
					"tile": tile,
				}

	return {}

# get the blocked area at specified position
# return value: array of Vector3 or Dictionary
func get_blocked_area(md: MapData, pos: Vector3, excluded_polyhedra: Array = []) -> Array:
	var ret: Array = []

	# check map data
	if md != null:
		ret += md.blocked_area.get(pos, [])

	# check polyhedron
	for obj in polyhedra:
		var poly: CuboidPolyhedron = obj as CuboidPolyhedron
		if poly != null and poly.map_data == md and not poly in excluded_polyhedra and poly.is_blocked_object():
			var local_pos: Vector3 = PolyhedronPosition.map_global_to_local(poly.map_position, pos)
			var tile: int = poly.get_tile(local_pos)
			if tile > 0:
				ret.push_back({
					"polyhedron": poly,
					"local_pos": local_pos,
					"tile": tile,
				})

	return ret

func _ready():
	if Engine.editor_hint:
		return

	for obj in get_children():
		if obj is CuboidPolyhedron:
			polyhedra.push_back(obj)
			obj.tween = tween
			obj.connect("input_event", self, "_on_input_event", [obj])

	select_next_polyhedron()

func _on_input_event(_camera: Node, event: InputEvent, _click_position: Vector3, _click_normal: Vector3, _shape_idx: int, obj: CuboidPolyhedron):
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT and event.pressed:
			if obj.is_selectable():
				select_polyhedron(obj)

func select_polyhedron(obj):
	var index: int = -1

	if obj is int:
		index = obj
	elif obj is CuboidPolyhedron:
		for i in range(polyhedra.size()):
			if obj == polyhedra[i]:
				index = i
				break

	selected_poly = polyhedra[index] if index >= 0 and index < polyhedra.size() else null
	for i in range(polyhedra.size()):
		polyhedra[i].selected = i == index

func select_next_polyhedron(direction: int = 1):
	if polyhedra.empty():
		return

	var index: int = -1

	for i in range(polyhedra.size()):
		if selected_poly == polyhedra[i]:
			index = i
			break

	if index < 0:
		index = polyhedra.size() - 1 if direction > 0 else 0

	var valid: bool = false

	for _i in range(polyhedra.size()):
		index += direction
		if index >= polyhedra.size():
			index -= polyhedra.size()
		elif index < 0:
			index += polyhedra.size()

		# check if new index is valid
		if index >= 0 and index < polyhedra.size() and polyhedra[index].is_selectable():
			valid = true
			break

	if valid and index >= 0 and index < polyhedra.size():
		select_polyhedron(index)

func _process(delta):
	if Engine.editor_hint:
		return

	if Input.is_action_just_pressed("ui_focus_next"):
		select_next_polyhedron(1)
		return
	elif Input.is_action_just_pressed("ui_focus_prev"):
		select_next_polyhedron(-1)
		return

	repeat_time -= delta
	if repeat_time > 0.0:
		return

	if tween.is_active():
		return

	if selected_poly == null:
		return

	var input: Vector3 = Vector3( \
		Input.get_action_strength("ui_up") - Input.get_action_strength("ui_down"), \
		Input.get_action_strength("ui_page_up") - Input.get_action_strength("ui_page_down"), \
		Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left"))

	if input.length_squared() > 0.25:
		var o: Vector3 = camera.get_transform().origin
		if o.x + o.z < 0:
			if o.z < o.x:
				var tmp: float = input.x
				input.x = -input.z
				input.z = tmp
		elif o.z < o.x:
			input.x = -input.x
			input.z = -input.z
		else:
			var tmp: float = input.x
			input.x = input.z
			input.z = -tmp
		selected_poly.process_move_input(input)
		repeat_time = 0.1
